﻿namespace RuoVea.OmiApi.SystemApp.Service;

/// <summary>
/// 系统角色服务🔷
/// </summary>
[ApiExplorerSettings(GroupName = "system")]
public class SysRoleService : IApplicationService
{
    private readonly ICurrentUser _currentUser;
    private readonly SugarRepository<SysRole> _sysRoleRep;
    private readonly SysRoleOrgService _sysRoleOrgService;
    private readonly SysRoleMenuService _sysRoleMenuService;
    private readonly SysOrgService _sysOrgService;
    private readonly SysUserRoleService _sysUserRoleService;
    private readonly SysCacheService _sysCacheService;
    /// <summary>
    /// 
    /// </summary>
    /// <param name="currentUser"></param>
    /// <param name="sysRoleRep"></param>
    /// <param name="sysRoleOrgService"></param>
    /// <param name="sysRoleMenuService"></param>
    /// <param name="sysOrgService"></param>
    /// <param name="sysUserRoleService"></param>
    /// <param name="sysCacheService"></param>
    public SysRoleService(ICurrentUser currentUser,
        SugarRepository<SysRole> sysRoleRep,
        SysRoleOrgService sysRoleOrgService,
        SysRoleMenuService sysRoleMenuService,
        SysOrgService sysOrgService,
        SysUserRoleService sysUserRoleService, SysCacheService sysCacheService)
    {
        _currentUser = currentUser;
        _sysRoleRep = sysRoleRep;
        _sysRoleOrgService = sysRoleOrgService;
        _sysRoleMenuService = sysRoleMenuService;
        _sysOrgService = sysOrgService;
        _sysUserRoleService = sysUserRoleService;
        _sysCacheService = sysCacheService;
    }

    /// <summary>
    /// 获取角色分页列表 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("获取角色分页列表")]
    public async Task<PageResult<SysRoleDto>> Page(PageRoleInput input)
    {
        // 当前用户已拥有的角色集合
        var roleIdList = _currentUser.IsSuperAdmin ? new List<long>() : await _sysUserRoleService.GetUserRoleIdList(_currentUser.UserId);
        return await _sysRoleRep.AsQueryable()
            //.LeftJoin<SysRoleOrg>((u,m)=>u.Id==m.RoleId)
            .WhereIF(!_currentUser.IsSuperAdmin && !_currentUser.IsTenantAdmin, u => u.Creator == _currentUser.UserId || roleIdList.Contains(u.Id)) // 若非超管且非系统管理员，则只能操作自己创建的角色
            .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
            .WhereIF(!string.IsNullOrWhiteSpace(input.Code), u => u.Code.Contains(input.Code))
            //.GroupBy((u, m) => u.Id)
            //.Select<SysRoleDto>()
            .Select((u) => new SysRoleDto
            {
                OrgIds = SqlFunc.Subqueryable<SysRoleOrg>().Where(m => m.RoleId == u.Id).ToList(m => m.OrgId)
            }, true)
            .OrderBy(u => new { u.Sort, u.Id })
            .ToPageAsync(input.PageNo, input.PageSize);
    }

    /// <summary>
    /// 获取角色列表 🔹
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取角色列表")]
    public async Task<List<RoleOutput>> GetList()
    {
        // 当前用户已拥有的角色集合
        var roleIdList = _currentUser.IsSuperAdmin ? new List<long>() : await _sysUserRoleService.GetUserRoleIdList(_currentUser.UserId);

        return await _sysRoleRep.AsQueryable()
            .WhereIF(!_currentUser.IsSuperAdmin && !_currentUser.IsTenantAdmin, u => u.Creator == _currentUser.UserId || roleIdList.Contains(u.Id)) // 若非超管且非系统管理员，则只显示自己创建和已拥有的角色
            .Where(u => u.IsDisable == YesOrNot.N) // 非禁用的
            .OrderBy(u => new { u.Sort, u.Id }).Select<RoleOutput>().ToListAsync();
    }

    /// <summary>
    /// 增加角色 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost]
    [DisplayName("增加角色")]
    public async Task AddRole(AddRoleInput input)
    {
        if (await _sysRoleRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code))
            throw new ArgumentException(i18n.data_exists);
        var newRole = await _sysRoleRep.AsInsertable(input.Adapt<SysRole>()).ExecuteReturnEntityAsync();
        input.Id = newRole.Id;
        //await UpdateRoleMenu(input);
        await GrantDataScope(new RoleOrgInput { Id = input.Id, DataScope = (int)input.DataScope, OrgIdList = input.OrgIds });
    }

    ///// <summary>
    ///// 更新角色菜单权限
    ///// </summary>
    ///// <param name="input"></param>
    ///// <returns></returns>
    //private async Task UpdateRoleMenu(AddRoleInput input)
    //{
    //    if (input.MenuIdList == null || input.MenuIdList.Count < 1)
    //        return;
    //    // 将父节点为0的菜单排除，防止前端全选异常
    //    var pMenuIds = await _sysRoleRep.ChangeRepository<SugarRepository<SysMenu>>().AsQueryable().Where(u => input.MenuIdList.Contains(u.Id) && u.Pid == 0).ToListAsync(u => u.Id);
    //    var menuIds = input.MenuIdList.Except(pMenuIds); // 差集
    //    await GrantMenu(new RoleMenuInput()
    //    {
    //        Id = input.Id,
    //        MenuIdList = menuIds.ToList()
    //    });
    //}

    /// <summary>
    /// 更新角色 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPut]
    [DisplayName("更新角色")]
    public async Task UpdateRole(UpdateRoleInput input)
    {
        if (await _sysRoleRep.IsAnyAsync(u => u.Name == input.Name && u.Code == input.Code && u.Id != input.Id))
            throw new ArgumentException(i18n.data_exists);

        await _sysRoleRep.AsUpdateable(input.Adapt<SysRole>()).IgnoreColumns(true)
            .IgnoreColumns(u => new { u.DataScope }).ExecuteCommandAsync();

        //await UpdateRoleMenu(input);
        await GrantDataScope(new RoleOrgInput { Id=input.Id, DataScope=(int)input.DataScope, OrgIdList= input.OrgIds });
    }

    /// <summary>
    /// 删除角色 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [UnitOfWork]
    [HttpDelete]
    [DisplayName("删除角色")]
    public async Task DeleteRole([FromBody] DeleteRoleInput input)
    {
        // 禁止删除系统管理员角色
        var sysRole = await _sysRoleRep.GetFirstAsync(u => u.Id == input.Id) ?? throw new ArgumentException(i18n.record_not_exists);
        if (sysRole.Code == CommonConst.SysAdminRole)
            throw new ArgumentException(i18n.prohibit_delete_admin);

        // 若角色有用户则禁止删除
        var userIds = await _sysUserRoleService.GetUserIdList(input.Id);
        if (userIds != null && userIds.Count > 0)
            throw new ArgumentException(i18n.role_has_accounts);

        await _sysRoleRep.DeleteAsync(sysRole);

        // 级联删除角色机构数据
        await _sysRoleOrgService.DeleteRoleOrgByRoleId(sysRole.Id);

        // 级联删除用户角色数据
        await _sysUserRoleService.DeleteUserRoleByRoleId(sysRole.Id);

        // 级联删除角色菜单数据
        await _sysRoleMenuService.DeleteRoleMenuByRoleId(sysRole.Id);
    }

    /// <summary>
    /// 授权角色菜单 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [UnitOfWork]
    [DisplayName("授权角色菜单")]
    public async Task GrantMenu(RoleMenuInput input)
    {
        await _sysRoleMenuService.GrantRoleMenu(input);
    }

    /// <summary>
    /// 授权角色数据范围 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [UnitOfWork]
    [DisplayName("授权角色数据范围")]
    public async Task GrantDataScope(RoleOrgInput input)
    {
        // 删除与该角色相关的用户机构缓存
        var userIdList = await _sysUserRoleService.GetUserIdList(input.Id);
        foreach (var userId in userIdList)
        {
            _sysCacheService.DeleteUserOrgCache(userId, _sysRoleRep.Context.CurrentConnectionConfig.ConfigId.ToString());
        }

        var role = await _sysRoleRep.GetFirstAsync(u => u.Id == input.Id);
        var dataScope = input.DataScope;
        if (!_currentUser.IsSuperAdmin)
        {
            // 非超级管理员没有全部数据范围权限
            if (dataScope == (int)DataScopeType.ALL)
                throw new ArgumentException(i18n.no_permission);

            // 若数据范围自定义，则判断授权数据范围是否有权限
            if (dataScope == (int)DataScopeType.DEFINE)
            {
                var grantOrgIdList = input.OrgIdList;
                if (grantOrgIdList.Count > 0)
                {
                    var orgIdList = await _sysOrgService.GetUserOrgIdList();
                    if (orgIdList.Count < 1)
                        throw new ArgumentException(i18n.no_permission);
                    else if (!grantOrgIdList.All(u => orgIdList.Any(c => c == u)))
                        throw new ArgumentException(i18n.no_permission);
                }
            }
        }
        role.DataScope = (DataScopeType)dataScope;
        await _sysRoleRep.AsUpdateable(role).UpdateColumns(u => new { u.DataScope }).ExecuteCommandAsync();
        await _sysRoleOrgService.GrantRoleOrg(input);
    }

    /// <summary>
    /// 根据角色Id获取菜单Id集合 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("根据角色Id获取菜单Id集合")]
    public async Task<List<long>> GetOwnMenuList([FromQuery] RoleInput input)
    {
        return await _sysRoleMenuService.GetRoleMenuIdList(new List<long> { input.Id });
    }

    /// <summary>
    /// 根据角色Id获取机构Id集合 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("根据角色Id获取机构Id集合")]
    public async Task<List<long>> GetOwnOrgList([FromQuery] RoleInput input)
    {
        return await _sysRoleOrgService.GetRoleOrgIdList(new List<long> { input.Id });
    }

    /// <summary>
    /// 设置角色状态 🔹
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [DisplayName("设置角色状态")]
    public async Task<int> SetStatus(RoleInput input)
    {
        if (!input.IsDisable.IsDefined<YesOrNot>())
            throw new ArgumentException(i18n.dict_status_error);

        return await _sysRoleRep.AsUpdateable()
            .SetColumns(u => u.IsDisable == input.IsDisable)
            .Where(u => u.Id == input.Id)
            .ExecuteCommandAsync();
    }
}